import requests
from functools import wraps
import random
import time
from logger import logger_main


# --- 通用重试配置 ---
DEFAULT_MAX_RETRIES = 2  # 总共尝试 3 次
DEFAULT_BASE_DELAY = 1.0  # 基础等待秒数


def retry_on_failure(max_retries=DEFAULT_MAX_RETRIES, base_delay=DEFAULT_BASE_DELAY):
    """
    一个用于封装请求函数的装饰器，实现带指数退避和抖动的重试机制。

    参数:
    - max_retries: 最大重试次数。
    - base_delay: 基础等待秒数（用于指数退避计算）。
    """
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            # 要捕获的异常类型 (通常是所有 requests 相关的异常)
            RETRYABLE_EXCEPTIONS = [
                requests.exceptions.RequestException,  # 包含 Timeout, ConnectionError, HTTPError
            ]
            # 动态导入 OpenAI 异常(如果已安装)
            try:
                from openai import InternalServerError, APITimeoutError
                RETRYABLE_EXCEPTIONS.extend([
                    InternalServerError,  # 503 等服务端错误
                    APITimeoutError,      # 超时错误
                ])
            except ImportError:
                pass

            RETRYABLE_EXCEPTIONS = tuple(RETRYABLE_EXCEPTIONS)
            for attempt in range(max_retries + 1):
                try:
                    # **1. 尝试执行原始函数**
                    result = func(*args, **kwargs)
                    # 假定函数执行成功，但您可能需要在此处添加对返回结果的额外检查
                    # 例如，检查 API 返回的特定错误码 (如果 API 不使用 HTTP 错误码)
                    if attempt > 0:
                        logger_main.info(f"请求成功 (尝试次数: {attempt + 1})")
                    return result

                # **2. 捕获可重试的异常**
                except RETRYABLE_EXCEPTIONS as e:
                    # 如果不是最后一次尝试，则进行重试前的处理
                    if attempt < max_retries:

                        # --- 指数退避与抖动计算 ---
                        # 计算基础指数延迟: base_delay * (2 ^ attempt)
                        # 例如: 1s, 2s, 4s, 8s...
                        base_wait = base_delay * (2 ** attempt)

                        # 引入随机抖动: 在 [base_wait * 0.5, base_wait * 1.5] 之间随机等待
                        # 避免大量并发请求同时重试，造成二次拥堵
                        wait_time = base_wait * (0.5 + random.random())

                        logger_main.warning(
                            f"❌ 请求失败 (尝试 {attempt + 1}/{max_retries + 1})，"
                            f"准备等待 {wait_time:.2f} 秒后重试: {type(e).__name__} - {e}"
                        )
                        time.sleep(wait_time)
                    else:
                        # **3. 最终失败**
                        logger_main.error(
                            f"❌ 请求最终失败 (总共尝试 {max_retries + 1} 次): {type(e).__name__} - {e}"
                        )
                        # 抛出最后的异常，让上层调用者处理
                        raise

                # **4. 捕获不可重试的异常**
                except Exception as e:
                    logger_main.error(
                        f"❌ 请求遇到不可重试的意外错误: {type(e).__name__} - {e}")
                    raise

            # 理论上不会走到这里，但作为安全措施
            return None

        return wrapper
    return decorator


def get_room_electricity_info():
    """
    获取宿舍的剩余电量信息
    """
    url = "https://application.xiaofubao.com/app/electric/queryRoomSurplus"
    headers = {
        "Cookie": "shiroJID=566ba8b2-d6b8-40a1-8d8c-aafd06e25238",
    }
    data = {
        "areaId": "2411589629028057089",  # 区域ID
        "buildingCode": "18",           # 楼栋代码
        "floorCode": "1008",            # 楼层代码
        "roomCode": "4575",             # 房间代码
        "platform": "YUNMA_APP"         # 平台标识
    }
    response = requests.post(
        url=url,
        headers=headers,
        data=data,
        verify=True,
        timeout=10
    )
    data = response.json()
    return data.get("data", {}).get("surplus", None)
    # {
    #     "statusCode": 0,
    #     "message": "操作成功",
    #     "data": {
    #         "surplus": 163.67,
    #         "amount": 0.0,
    #         "isShowSurplus": 0,
    #         "isShowMoney": 1,
    #         "remind": "",
    #         "system": 0,
    #         "displayRoomName": "浙江广厦大学木雕小镇校区D5B宿舍楼D5-B8层D5-B818",
    #         "footerLink": 0,
    #         "canBuy": 0,
    #         "showSplit": 0
    #     },
    #     "success": true
    # }
